#include <stdio.h>
#include <string.h>

#include "util.h"
#include "xml.h"

struct pos {
	char lat[16];
	char lon[16];
};

static XMLParser parser; /* XML parser state */
static char curelement[32];
static char curgpxelement[16];
static struct pos pos;
static int linkindex;
static int trksegindex;

static int
istag(const char *s1, const char *s2)
{
	return !strcasecmp(s1, s2);
}

static int
isattr(const char *s1, const char *s2)
{
	return !strcasecmp(s1, s2);
}

void
xml_handler_start_element(XMLParser *p, const char *tag, size_t taglen)
{
	if (istag(tag, "gpx")) {
		printf("---\n");
		printf("type: FeatureCollection\n");
		printf("features:\n");
	} else if (istag(tag, "wpt")) {
		strlcpy(curgpxelement, tag, sizeof(curgpxelement));
		memset(&pos, 0, sizeof(pos));
		linkindex = 1;
		printf("- type: Feature\n");
		printf("  properties:\n");
	} else if (istag(tag, "trk")) {
		strlcpy(curgpxelement, tag, sizeof(curgpxelement));
		linkindex = 1;
		trksegindex = 1;
		printf("- type: Feature\n");
		printf("  properties:\n");
	} else if (istag(tag, "name") || istag(tag, "desc") || istag(tag, "type") ||
	           istag(tag, "text") || istag(tag, "gpxtrkx:Distance") ||
	           istag(tag, "gpxtrkx:Ascent") || istag(tag, "gpxtrkx:Descent") ||
	           istag(tag, "gpxtrkx:MovingTime") || istag(tag, "gpxtrkx:StoppedTime")) {
		strlcpy(curelement, tag, sizeof(curelement));
	} else if (istag(tag, "trkseg")) {
		if (trksegindex == 1) {
			printf("  geometry:\n");
			printf("    type: LineString\n");
			printf("    coordinates:\n");
		}
		trksegindex++;
	} else if (istag(tag, "trkpt")) {
		memset(&pos, 0, sizeof(pos));
	}
}

void
xml_handler_end_element(XMLParser *p, const char *tag, size_t taglen, int isshort)
{
	if (istag(tag, "wpt")) {
		curgpxelement[0] = '\0';
		printf("  geometry:\n");
		printf("    type: Point\n");
		printf("    coordinates:\n");
		printf("    - %s\n", pos.lon);
		printf("    - %s\n", pos.lat);
	} else if (istag(tag, "trk")) {
		curgpxelement[0] = '\0';
	} else if (istag(tag, "name") || istag(tag, "desc") || istag(tag, "type") ||
	           istag(tag, "text") || istag(tag, "gpxtrkx:Distance") ||
	           istag(tag, "gpxtrkx:Ascent") || istag(tag, "gpxtrkx:Descent") ||
	           istag(tag, "gpxtrkx:MovingTime") || istag(tag, "gpxtrkx:StoppedTime")) {
		curelement[0] = '\0';
	} else if (istag(tag, "link")) {
		linkindex++;
	} else if (istag(tag, "trkpt")) {
		printf("    - - %s\n", pos.lon);
		printf("      - %s\n", pos.lat);
	}
}

void
xml_handler_attr(XMLParser *p, const char *tag, size_t taglen, const char *name, size_t namelen,
        const char *value, size_t valuelen)
{
	if (strcmp(curgpxelement, "wpt") != 0 && strcmp(curgpxelement, "trk") != 0)
		return;

	if (istag(tag, "wpt") || istag(tag, "trkpt")) {
		if (isattr(name, "lat")) {
			strlcpy(pos.lat, value, sizeof(pos.lat));
		} else if (isattr(name, "lon")) {
			strlcpy(pos.lon, value, sizeof(pos.lon));
		}
	} else if (istag(tag, "link")) {
		if (isattr(name, "href")) {
			printf("    link%d_href: \"%s\"\n", linkindex, value);
		}
	}
}

void
xml_handler_data(XMLParser *p, const char *data, size_t datalen)
{
	if (strcmp(curgpxelement, "wpt") != 0 && strcmp(curgpxelement, "trk") != 0)
		return;

	if (strcmp(curelement, "name") == 0) {
		printf("    name: \"%s\"\n", data);
	} else if (strcmp(curelement, "desc") == 0) {
		printf("    desc: \"%s\"\n", data);
	} else if (strcmp(curelement, "type") == 0) {
		printf("    type: \"%s\"\n", data);
	} else if (strcmp(curelement, "text") == 0) {
		printf("    link%d_text: \"%s\"\n", linkindex, data);
	} else if (strcmp(curelement, "gpxtrkx:Distance") == 0) {
		printf("    distance: %s\n", data);
	} else if (strcmp(curelement, "gpxtrkx:Ascent") == 0) {
		printf("    ascent: %s\n", data);
	} else if (strcmp(curelement, "gpxtrkx:Descent") == 0) {
		printf("    descent: %s\n", data);
	} else if (strcmp(curelement, "gpxtrkx:MovingTime") == 0) {
		printf("    moving_time: %s\n", data);
	} else if (strcmp(curelement, "gpxtrkx:StoppedTime") == 0) {
		printf("    stopped_time: %s\n", data);
	}
}

int
main(void)
{
	parser.xmltagstart = xml_handler_start_element;
	parser.xmltagend = xml_handler_end_element;
	parser.xmlattr = xml_handler_attr;
	parser.xmldata = xml_handler_data;

	parser.getnext = getchar;

	xml_parse(&parser);

	return 0;
}
